/*
  Instances of this class classify objects detected in the tracking process as person, group, car, truck, etc.
  To do that, fuzzy rules learned by another software application are used. It is also needed a file where
  fuzzy variables and fuzzy sets are specified.

*/
import java.util.Vector;
import java.util.StringTokenizer;
import java.io.*;
import java.sql.*;

class ObjectClassifier{
	
    protected Vector<FuzzyClass> v_classes;
    protected Vector<FuzzyVariable> v_variables;	
    protected Vector<FuzzyObject> v_objects; //objects used in the classification process.
    
    public ObjectClassifier(){
	v_variables = new Vector();
	v_classes = new Vector();
	v_objects = new Vector();
    }
    //loadVariables: load the information regarding the variables from a input file.
    public void loadVariables(String file){
	FileReader f_variables;
       
	try{
	    f_variables = new FileReader(file);
	    BufferedReader bf = new BufferedReader(f_variables);
	    String sLine;

	    while ((sLine = bf.readLine())!=null) {
		if(sLine.charAt(0)=='#'){
		    //the name of a variable
		    FuzzyVariable fv = new FuzzyVariable(sLine.substring(1,sLine.length()));
		    this.v_variables.add(fv);
		}else{
		    //including fuzzy sets on the variables.
		    StringTokenizer st = new StringTokenizer(sLine, ":");
		    String label = st.nextToken();
		    String values = st.nextToken();
		    st = new StringTokenizer(values, ",");
		    float a = Float.valueOf(st.nextToken());
		    float b = Float.valueOf(st.nextToken());
		    float c = Float.valueOf(st.nextToken());
		    float d = Float.valueOf(st.nextToken());

		    FuzzySet fs = new FuzzySet(label,a,b,c,d);
		    FuzzyVariable fv = this.v_variables.elementAt(this.v_variables.size()-1);
		    fv.addFuzzySet(fs);
		}
	    }//end while
	}catch(Exception e){
	    System.out.println("Error while loading variables information: "+e);
	}//end catch	
    }//end loadVariables
    
    //print the variables and their values on the screen
    public void printVariables(){
	
	for(int i=0; i< this.v_variables.size();i++){
	    FuzzyVariable fv = this.v_variables.elementAt(i);
	    System.out.println(fv.getName());
	    for(int j=0; j< fv.getNumberFuzzySets();j++){
		FuzzySet fs = fv.getFuzzySetAt(j);
		System.out.println(fs.getLabel()+":"+fs.getA()+","+fs.getB()+","+fs.getC()+","+fs.getD());
	    }//for
	}//end for
    }//end printVariables

    //loadRules: loadVariables must be called before this method. Variables are needed to build the set of rules.
    public void loadRules(String file){
	FileReader f_rules;
       
	try{
	    f_rules = new FileReader(file);
	    BufferedReader bf = new BufferedReader(f_rules);
	    String sLine;

	    while ((sLine = bf.readLine())!=null) {
		if(sLine.charAt(0)=='#'){
		    //the name of a variable
		    FuzzyClass fc = new FuzzyClass(sLine.substring(1,sLine.length()));
		    this.v_classes.add(fc);
		}else{
		    //including  fuzzy rules on classes.
		    StringTokenizer st = new StringTokenizer(sLine, ";");
		    int number_variable = 0;
		    FuzzyRule fr = new FuzzyRule();
		    
		    while(st.hasMoreTokens()){
			//every token corresponds with a variable
			String rule_fragment = st.nextToken();
			FuzzyVariable fv = new FuzzyVariable(((FuzzyVariable)this.v_variables.elementAt(number_variable)).getName());
			if(rule_fragment.charAt(0)=='{'){
			    //all fuzzy sets of the variable are included in the rule.
			    fr.addVariable(fv);
			}else{
			    StringTokenizer st2 = new StringTokenizer(rule_fragment, "|");
			    //Every token is a fuzzy set of the current variable
			    while (st2.hasMoreTokens()){
				String s_fuzzy_sets = st2.nextToken();
				//every token is a tuple such as (a,b,c,d)
				s_fuzzy_sets = s_fuzzy_sets.substring(1,s_fuzzy_sets.length()-1);
				StringTokenizer st3 = new StringTokenizer(s_fuzzy_sets, ",");
				
				float a = Float.valueOf(st3.nextToken());
				float b = Float.valueOf(st3.nextToken());
				float c = Float.valueOf(st3.nextToken());
				float d = Float.valueOf(st3.nextToken());

				FuzzySet fs = new FuzzySet("",a,b,c,d);
				fv.addFuzzySet(fs);				
			    }//end while
			    fr.addVariable(fv);
			}
			number_variable++;
		    }//end while
		    FuzzyClass fc = this.v_classes.elementAt(v_classes.size()-1);
		    fc.addRule(fr);
		}//end else 
	    }//end while
	}catch(Exception e){
	    System.out.println("Error while loading rules on the classes: "+e);
	}//end catch	
    }//end loadVariables

    public void printRules(){
	System.out.println("-----------RULES-----------");
	for(int i=0;i< this.v_classes.size();i++){
	    FuzzyClass fc = this.v_classes.elementAt(i);
	    System.out.println("#"+fc.getName());
	    for(int j=0;j<fc.numRules();j++){
	       
		FuzzyRule fr = fc.getRuleAt(j);
		for(int w=0; w < this.v_variables.size();w++){
		    FuzzyVariable fv = fr.getFuzzyVariableAt(w);
		    if(fv.getNumberFuzzySets() == 0)
			System.out.print("{_};");
		    else{
			for(int z=0;z<fv.getNumberFuzzySets();z++){
			    FuzzySet fs = fv.getFuzzySetAt(z);
			    System.out.print("("+fs.getA()+","+fs.getB()+","+fs.getC()+","+fs.getD()+")");
			}//end for - while there are fuzzy sets
			System.out.print(";");
		    }
		}//end for, while there are variables 
		System.out.println("");
	    }//end for - while there are rules
	}//end for - while there are classes
    }//end printRules


    public FuzzyObject classify(String id, Vector v_values){
	//this method classify one object using the learned rules and earlier classifications (tracking is taken into
	//account to classify objects).
	
	FuzzyObject fo = null;
	for(int i=0;i<this.v_objects.size();i++){
	    FuzzyObject tmp = v_objects.elementAt(i);
	    if((tmp.getId()).equals(id))
		fo = tmp;
	}//end for		
	if(fo == null){
	    fo = new FuzzyObject(id);
	    this.v_objects.add(fo);
	}

	//how object id belongs to the classes.

	for(int i=0;i < this.v_classes.size();i++){
	    FuzzyClass fc = this.v_classes.elementAt(i);
	    float membership_class = fc.membershipValue(v_values);	    

	    //updating v_objects
	   
		MembershipOC mship = fo.getMembershipByClass(fc.getName());
		if(mship == null){
		    mship = new MembershipOC(fc.getName());		    
		    fo.addMembership(mship);		    
		}
		mship.sumMembershipValue(membership_class);
		mship.incrementTimes();
	    	    
	}//end for
	
	return fo;
    }//end classify

    
    
}//end class
